

#include "xmodule_config.h"

#if MODULE_TOUCHPANEL_ENABLE && (TP_CHIP_TYPE == TP_CHIP_CST716D)


#if TPL_FIRMWARE_UPGRADE_SUPPORTED
#include TP_FIRMWARE_FILE
#endif

#ifndef FIRMWARE_VERSION_716
#define FIRMWARE_VERSION_716       TP_FIRMWARE_VERSION
#endif

#define APP_SLAVE_ADDR           0x15
#define BOOT_SLAVE_ADDR          0x6A

#define CTP_DEV_ID_ADDR              0xA7
#define CTP_VER_ADDR                 0xA9
#define CTP_SLEEP_ADDR               0xA5

#define CTP_DEV_ID_716              0x20 
#define CTP_SLEEP_CMD                0x03 


//static uint8_t m_tp_dfu_write_perent = 0;

/////////////////////////////////////////////////////////////////////
static bool __cst716_read_byte( uint8_t reg, uint8_t* data)
{
    uint32_t ret = TP_APP_READ_BYTE( reg, data );
    if( ret != TP_I2C_SUCCESS )
    {
        LOG1("[TP]: read fail, ret = 0x%X", ret );
    }
    return ret == TP_I2C_SUCCESS;
}
static bool __cst716_write_byte( uint8_t reg, uint8_t data)
{
    uint8_t write[2] = {reg, data };
    uint32_t ret = TP_APP_WRITE_BYTE( 0, write);
    if( ret != TP_I2C_SUCCESS )
    {
        // print error info 
    }
    
    return ret == TP_I2C_SUCCESS;
}
static bool __cst716_read_bytes( uint8_t reg, uint8_t* data, uint16_t len)
{
    uint32_t ret = TP_APP_READ_BYTES( reg, data, len);
    if( ret != TP_I2C_SUCCESS )
    {
        LOG1("[TP]:1 r err = 0x%X", ret );
    }
    
    return ret == TP_I2C_SUCCESS;
}


bool em_touch_panel_mounting(uint8_t* p_chip_id, uint8_t* p_version)
{
    int i ;    
    uint8_t chip_id = CTP_DEV_ID_716 + 1; // incase TP_DEV_ID = 0
    bool result = false;
 
    TP_SET_RESET;
    TP_OS_DELAY_MS(5);
    TP_SET_nRESET;   
    TP_OS_DELAY_MS(20);
        
    TP_I2C_SLAVE_ADDR_SET( APP_SLAVE_ADDR );
    // check device id 
    for( i = 0; i < 10; i ++ ) 
    {
        if( __cst716_read_byte( CTP_DEV_ID_ADDR, &chip_id )  )
        {
            LOG1("[TP]: chip id = 0x%X", chip_id ); 
            if( chip_id == CTP_DEV_ID_716 )
            {
                result = true; 
                break;
            }
        }
        
        TP_OS_DELAY_MS( 20 );
    }
    if( result )
    {    
        // check version 
        uint8_t version = 0;
        bool ret = __cst716_read_byte( CTP_VER_ADDR, &version );
        if( ret )
        {
            LOG1("[TP]: version = %d", version );
            if( chip_id == CTP_DEV_ID_716 && version == FIRMWARE_VERSION_716 )
            {
                *p_chip_id = chip_id;
                *p_version = version;

                tp_enable();
                return true;
            }
        }
    }
     
    
    return false;    
}

void em_touch_panel_update(void)
{
    uint8_t data[6];
    TP_I2C_SLAVE_ADDR_SET( APP_SLAVE_ADDR );
    #if TP_REPORT_MODE == 0// pts mode 
    if( __cst716_read_bytes( 0x03, data, 4 ))
    {        
        if( (data[0] & 0xC0) != 0x40 )
        {
            touch_raw_data_t* p = tp_fifo_get_write();
            p->flag = TP_ALGO_FLAG_DOWN;
		    p->x = ((data[0] & 0x0f) << 8) | data[1];
            p->y = ((data[2] & 0x0f) << 8) | data[3];
		//APP_PRINT_INFO6("[TP-1]: data1 = %d,%d,%d,%d,x=%d,y=%d", data[0],data[1],data[2],data[3],p->x,p->y );	

        }
    }
    #elif TP_REPORT_MODE == 1 
    // gesture mode 
    if( __cst716_read_bytes( 0x01, data, 6))
    {
        // if( data[1] == 0 ) //no finger 
        // {
        //     return;
        // }
        touch_raw_data_t* p = tp_fifo_get_write();
        p->flag = data[0]; // gesture
        p->x    = data[4];  // 3
        p->y    = data[6];  // 5 
    }
    #else 
    // nothings to do 
    #endif
}
void em_touchpanel_enable(void)
{
    tp_enable();
}

void em_touchpanel_disable(void)
{    
    TP_I2C_SLAVE_ADDR_SET( APP_SLAVE_ADDR );
    __cst716_write_byte( CTP_SLEEP_ADDR, CTP_SLEEP_CMD );
    
    tp_disable();    
}

#if TPL_FIRMWARE_UPGRADE_SUPPORTED // Boot Mode 
#define TP_PKT_LEN      512
#define TP_FIRMWARE_OFFSET  6 
typedef struct 
{
    uint8_t*    pcontext;
    uint32_t    start_address;
    uint32_t    size;
    uint32_t    crc;
}tp_boot_ctl_t;
typedef struct
{
    uint16_t reg;
    uint8_t data[512];
}tp_boot_data_t; 
typedef struct
{
    uint16_t reg;
    uint8_t data[4];
}tp_boot_cmd_t;

static bool boot_enter(void)
{
    TP_SET_RESET;
    TP_DELAY_MS( 10 );
    TP_SET_nRESET;
	TP_OS_DELAY_MS(10);				   
    
//    uint16_t ret;
    int retry_cnt = 10;
    
    tp_boot_cmd_t write;
    
    while( retry_cnt -- ) 
    {
        write.reg = 0x01A0;
        write.data[0] = 0xAA;
        if( TP_BOOT_WRITE_BYTES( write.reg, write.data, 1 ) != TP_I2C_SUCCESS )
        {
            TP_DELAY_MS( 2 ); 
            continue;
        }
        
        write.reg = 0x03A0;
        if( TP_BOOT_READ_BYTES( write.reg, write.data, 1 ) != TP_I2C_SUCCESS )
        {
            TP_DELAY_MS( 2 );
            continue;
        }
        
        if( write.data[0] != 0x55 ) 
        {
            TP_DELAY_MS( 2 );
            continue;
        }
        
        return true;
    }
    
    return false;
}

static bool boot_set_chip_compute_checksum(void)
{
    tp_boot_cmd_t write;
    write.reg = 0x03A0;
    write.data[0] = 0x00;
    return TP_BOOT_WRITE_BYTES( write.reg, write.data, 1 ) == TP_I2C_SUCCESS ;
}
static bool boot_get_chip_compute_checksum(uint16_t* checksum)
{
    tp_boot_cmd_t write;
    write.reg = 0x08A0;//0xA008;
    return TP_BOOT_READ_BYTES( write.reg, (uint8_t*)checksum, 2 ) == TP_I2C_SUCCESS;
}
static bool boot_write_firmware(uint32_t address, uint8_t *data, uint16_t size )
{
    tp_boot_cmd_t write;
    // write address 
    {
        write.reg = 0x14A0;//0xA014;
        write.data[0] = address & 0xff;
        write.data[1] = address >> 8;
        TP_BOOT_WRITE_BYTES( write.reg, write.data, 2);
    }
    // write size 
    {
        tp_boot_data_t write_data;
        write_data.reg = 0x18A0;//0xA018;
        memcpy( write_data.data, data, size );
        TP_BOOT_WRITE_BYTES( write_data.reg, data, size );
        TP_DELAY_MS(1);
    }
    // write content 
    {
        write.reg = 0x04A0;//0xA004;
        write.data[0] = 0xEE;        
        TP_BOOT_WRITE_BYTES( write.reg, write.data, 1 );
    }
    return true;
}
static bool boot_wait_idle(void)
{
    int retry_cnt = 50;  

//    uint16_t reg = 0xA005;
    tp_boot_cmd_t write;
    write.reg = 0x05A0;//0xA005;
    while (retry_cnt --)
    {
        write.data[0] = 0x00;
        if( TP_BOOT_READ_BYTES( write.reg, write.data, 1) == TP_I2C_SUCCESS)
        {
            if( write.data[0] == 0x55 )
            {
                return true;
            }
            TP_OS_DELAY_MS( 10 );
        }
    }
    
    return false;
}
static bool boot_exit(void)
{
    tp_boot_cmd_t write;
    write.reg = 0x03A0;//0xA003;
    write.data[0] = 0x00;
    return TP_BOOT_WRITE_BYTES( write.reg, write.data, 1) == TP_I2C_SUCCESS;
}
static void boot_reset(void)
{
    TP_SET_RESET;
    TP_OS_DELAY_MS( 10 );
    TP_SET_nRESET;
    TP_OS_DELAY_MS( 30 ); 
}

void em_touch_panel_boot_update( uint32_t firmware_address, uint8_t *ppercent ) 
{
    *ppercent = 0;

    TP_I2C_SLAVE_ADDR_SET( BOOT_SLAVE_ADDR );

    if( !boot_enter() ) 
    {
        LOG0("[TP]: enter boot FAIL");
        return; 
    }
    
    uint16_t checksum = 0;
    boot_set_chip_compute_checksum();
//    TP_DELAY_MS( 500 );
    TP_OS_DELAY_MS( 500 );
    
    if( !boot_get_chip_compute_checksum( &checksum ) ) 
    {
        LOG0("[TP]: boot get checksum FAIL");
        return; 
    }
    
    // use internal firmware
    if( firmware_address == 0 )
    {
        firmware_address = (uint32_t)app_bin;
    }
    
    uint8_t buf[ TP_PKT_LEN];
    tp_boot_ctl_t boot_ctl;
    boot_ctl.pcontext = (uint8_t*)firmware_address ;
    boot_ctl.start_address = uint16_decode( boot_ctl.pcontext );
    boot_ctl.size           = uint16_decode( boot_ctl.pcontext + 2);
    boot_ctl.crc            = uint16_decode( boot_ctl.pcontext + 4);
   
    if( checksum == boot_ctl.crc )
    {
        LOG0("[TP]: boot checksum equal, no need to upgrade");
        boot_reset();
        return;
    }
    boot_ctl.pcontext += TP_FIRMWARE_OFFSET;
    if( boot_ctl.size < 0x100 || boot_ctl.size > 0x6000 )
    {
        return;
    }
    
    do 
    {
        memcpy( buf , boot_ctl.pcontext + boot_ctl.start_address, TP_PKT_LEN );
        if( !boot_write_firmware( boot_ctl.start_address, buf, TP_PKT_LEN) )
        {
            break;
        }
        boot_ctl.start_address += TP_PKT_LEN;
        *ppercent = boot_ctl.start_address * 100 / boot_ctl.size ;
//        LOG1("[TP-BOOT]: write percent %d%%", *ppercent );
        
        TP_OS_DELAY_MS( 100 );
        if( !boot_wait_idle() )
        {
            break;
        }
    } while( boot_ctl.start_address < boot_ctl.size );

    boot_set_chip_compute_checksum();
    TP_OS_DELAY_MS( 500 );
    boot_get_chip_compute_checksum( &checksum );
    if( checksum != boot_ctl.crc )
    {
        // log check upgrade FAIL 
    }

    boot_exit();
    boot_reset();   
}
#else 
void em_touch_panel_boot_update(uint32_t firmware_address, uint8_t *ppercent )
{
    // nothings to 
}

#endif // !

#endif // !MODULE_TOUCHPANEL_ENABLE && (TP_CHIP_TYPE == TP_CHIP_CST716D)
